﻿using System;
using System.Linq;
using System.Collections.Generic;
using System.Text;
using OpenTK.Graphics.OpenGL;
using System.Data;
/// <summary>
/// Clase para manejar grandes cantidades de entidades de forma estatica
/// o para manejar pequeñas cantidades de entidades de forma dinamica
/// desde una base de datos 
/// </summary>
/// JS: Juan Antonio Sanjuan jauanntonios@gmail.com 
unsafe public class CapaSQL : IEntidad
{
    public Linea[] arrLineas;
    public Triangulo[] arrTriangulos;
    public Rectangulo[] arrRectangulo;

    /// <summary>
    /// Constructor por defecto para crear una capa que maneja muchas entidades a travez de SQL
    /// </summary>
    /// <param name="strIDCapa">ID único de capa</param>
    /// <param name="enmTipoEntidad">tipo de simbolo para la entidad</param>
    /// <param name="intTamanoMAX">Tamaño maximo</param>
    /// <param name="pSQL">Sentencia SQL que maneja la capa topologica</param>
    /// <param name="pEscena">Escenario donde se desea dibujar la capa</param>
    /// <param name="enmTipoCapa">Tipo de Capa  y comportamiento de la capa</param>
    /// <param name="objColor">Color de la entidad</param>
    /// <param name="intEntidadAlto">tamano alto de la entidad</param>
    /// <param name="intEntidadLargo">largo de la entidad</param>
    /// <param name="pAlturaMax">altura maxima permitida</param>
    /// <param name="alturaCapa">altura en coordenada z</param>
    /// <param name="strTabla">Nombre de la tabla o vista SQL para consultar puntualmente la informacion</param>
    public unsafe CapaSQL(string strIDCapa, TIPO_ENTIDAD enmTipoEntidad, int intTamanoMAX, string pSQL, Escenario pEscena, TIPO_CAPA_SQL enmTipoCapa, Colores objColor, float intEntidadAlto, float intEntidadLargo, int pAlturaMax, float alturaCapa, string strTabla)
    {
        this.ID = strIDCapa;
        switch (enmTipoEntidad)
        {
            case TIPO_ENTIDAD.Linea :
            {
                arrLineas = new Linea[intTamanoMAX];
                for (int i = 0; i < intTamanoMAX; i++)
                {
                    arrLineas[i] = new Linea();
                }
                break;
            }
            case TIPO_ENTIDAD.Rectangulo:
            {
                arrRectangulo = new Rectangulo[intTamanoMAX];
                for (int i = 0; i < intTamanoMAX; i++)
                {
                    arrRectangulo[i] = new Rectangulo();
                }
                break;
            }
            case TIPO_ENTIDAD.Triangulo:
            {
                arrTriangulos = new Triangulo[intTamanoMAX];
                for (int i = 0; i < intTamanoMAX; i++)
                {
                    arrTriangulos[i] = new Triangulo();
                }
                break;
            }
        }
        this._objEntidad = enmTipoEntidad;
        this.Visible = true;
        this.SQL = pSQL;
        this._TipoCapaSQL = enmTipoCapa;
        this.Coloreado = objColor;
        this.Escena = pEscena;
        this.EntidadAlto = intEntidadAlto;
        this.EntidadLargo = intEntidadLargo;
        this.AlturaMax = pAlturaMax;
        this.Alto = alturaCapa;
        this.Tabla = strTabla;
        this.Localizacion = new Coordenada(Escena.Localizacion.X, Escena.Localizacion.Y);
        Construir();
    }

    private Escenario _Escena;
    public Escenario Escena
    {
        get { return _Escena; }
        set { _Escena = value; }
    }

    private string _tabla;
    public string Tabla
    {
        get { return _tabla; }
        set { _tabla = value; }
    }

    float _EntidadAlto;
    public float EntidadAlto
    {
        get { return _EntidadAlto; }
        set { _EntidadAlto = value; }
    }

    float _EntidadLargo;
    public float EntidadLargo
    {
        get { return _EntidadLargo; }
        set { _EntidadLargo = value; }
    }

    /// <summary>
    /// Recorre las consulta SQL y convierte el resultado de tabla
    /// en entidades topologicas
    /// </summary>
    private unsafe void Construir()
    {
        this.IndiceActual = -1;
        string strConsulta = this.SQL;
        Coordenada objXY1 = this.Escena.coordenadasXY(1, 1);
        Coordenada objXY2 = this.Escena.coordenadasXY(Escena.Largo + 1f, Escena.Alto + 1f);
        if (this.TipoCapaSQL == TIPO_CAPA_SQL.DINAMICA && this.TipoEntidad==TIPO_ENTIDAD.Linea)
        {
            objXY1.X -= (this.Escena.Alto / 8);
            objXY1.Y += (this.Escena.Alto / 8);
            objXY2.X += (this.Escena.Alto / 8);
            objXY2.Y -= (this.Escena.Alto / 8);
        }
        strConsulta = strConsulta.Replace("{X1}", objXY2.X.ToString().Replace(",", "."));
        strConsulta = strConsulta.Replace("{X2}", objXY1.X.ToString().Replace(",", "."));
        strConsulta = strConsulta.Replace("{Y1}", objXY2.Y.ToString().Replace(",", "."));
        strConsulta = strConsulta.Replace("{Y2}", objXY1.Y.ToString().Replace(",", "."));
        DataTable objTabla = Conexion.ObtenerTabla(strConsulta);
        float r, g, b;
        r = 1f;
        g = 0f;
        b = 0f;
        Colores objColor = new Colores(50, 220, 150);
        if (this.Coloreado != null)
        {
            objColor = this.Coloreado;
            r = this.Coloreado.Rojo;
            g = this.Coloreado.Verde;
            b = this.Coloreado.Azul;
        }
        
        switch (this.TipoEntidad)
        {
            case TIPO_ENTIDAD.Linea:
                {
                    construirLineas( r, g, b, objTabla, 1, objColor);
                    break;
                }
            case TIPO_ENTIDAD.Rectangulo:
                {
                    construirRectangulos( r, g, b, objTabla, 1, objColor);
                    break;
                }
            case TIPO_ENTIDAD.Triangulo:
                {
                    construirTriangulos( r, g, b, objTabla, 1, objColor);
                    break;
                }
        }
        objTabla.Dispose();
    }

    /// <summary>
    /// Construye lineas topologicas
    /// </summary>
    /// <param name="r">rojo</param>
    /// <param name="g">verde</param>
    /// <param name="b">azul</param>
    /// <param name="objTabla"></param>
    /// <param name="fltFacTorDivision"></param>
    /// <param name="objColorLin"></param>
    protected unsafe void construirLineas(float r, float g, float b, DataTable objTabla, float fltFacTorDivision, Colores objColorLin)
    {
        foreach (DataRow objRegistro in objTabla.Rows)
        {
            IndiceActual++;
            //Depronto no se debe usar porque ya se sabe el maximmos desde el limite de base de datos
            /*if (IndiceActual == this.TamanoMax)
            {
                break;
            }*/
            float x, y, x2, y2;
            x = float.Parse(objRegistro["XPOS1"].ToString()) / fltFacTorDivision;
            y = float.Parse(objRegistro["YPOS1"].ToString()) / fltFacTorDivision;
            x2 = float.Parse(objRegistro["XPOS2"].ToString()) / fltFacTorDivision;
            y2 = float.Parse(objRegistro["YPOS2"].ToString()) / fltFacTorDivision;
            if (this.Coloreado == null)
            {
                r = float.Parse(objRegistro["R"].ToString());
                g = float.Parse(objRegistro["G"].ToString());
                b = float.Parse(objRegistro["B"].ToString());
                objColorLin = new Colores();
                objColorLin.SetOGL(r, g, b);
            }
            arrLineas[IndiceActual].Coloreado = objColorLin;
            arrLineas[IndiceActual].Localizacion = new Coordenada(x, y, this.Alto);
            arrLineas[IndiceActual].Localizacion2 = new Coordenada(x2, y2, this.Alto);
            arrLineas[IndiceActual].ID = objRegistro["CODE"].ToString();
        }
    }

    /// <summary>
    /// Construye Triangulos Topologicos
    /// </summary>
    /// <param name="r">rojo</param>
    /// <param name="g">verde</param>
    /// <param name="b">azul</param>
    /// <param name="objTabla"></param>
    /// <param name="fltFacTorDivision"></param>
    /// <param name="objColorLin"></param>
    protected unsafe void construirTriangulos(float r, float g, float b, DataTable objTabla, float fltFacTorDivision, Colores objColorLin)
    {
        foreach (DataRow objRegistro in objTabla.Rows)
        {
            IndiceActual++;
            //Depronto no se debe usar porque ya se sabe el maximmos desde el limite de base de datos
            /*if (IndiceActual == this.TamanoMax)
            {
                break;
            }*/
            float x, y;
            x = float.Parse(objRegistro["XPOS"].ToString()) / fltFacTorDivision;
            y = float.Parse(objRegistro["YPOS"].ToString()) / fltFacTorDivision;
            if (this.Coloreado == null)
            {
                r = float.Parse(objRegistro["R"].ToString());
                g = float.Parse(objRegistro["G"].ToString());
                b = float.Parse(objRegistro["B"].ToString());
                objColorLin = new Colores();
                objColorLin.SetOGL(r, g, b);
            }
            arrTriangulos[IndiceActual].Coloreado = objColorLin;
            arrTriangulos[IndiceActual].setParams(this.EntidadLargo / fltFacTorDivision, this.EntidadAlto / fltFacTorDivision, new Coordenada(x, y, this.Alto));
            arrTriangulos[IndiceActual].ID = objRegistro["CODE"].ToString();
        }
    }

    /// <summary>
    /// Construye Rectangulos Topologicos
    /// </summary>
    /// <param name="r">rojo</param>
    /// <param name="g">verde</param>
    /// <param name="b">azul</param>
    /// <param name="objTabla"></param>
    /// <param name="fltFacTorDivision"></param>
    /// <param name="objColorLin"></param>
    protected unsafe void construirRectangulos(float r, float g, float b, DataTable objTabla, float fltFacTorDivision, Colores objColorLin)
    {
        foreach (DataRow objRegistro in objTabla.Rows)
        {
            IndiceActual++;
            float x, y;
            x = float.Parse(objRegistro["XPOS"].ToString());
            y = float.Parse(objRegistro["YPOS"].ToString());
            if (this.Coloreado == null)
            {
                r = float.Parse(objRegistro["R"].ToString());
                g = float.Parse(objRegistro["G"].ToString());
                b = float.Parse(objRegistro["B"].ToString());
                objColorLin = new Colores();
                objColorLin.SetOGL(r, g, b);
            }
            arrRectangulo[IndiceActual].Coloreado = objColorLin;
            arrRectangulo[IndiceActual].setParams(this.EntidadLargo / fltFacTorDivision, this.EntidadAlto / fltFacTorDivision, new Coordenada(x, y, this.Alto));
            arrRectangulo[IndiceActual].ID = objRegistro["CODE"].ToString();            
        }
    }

    private int _IndiceActual;
    public int IndiceActual
    {
        get { return _IndiceActual; }
        set { _IndiceActual = value; }
    }

    private string SQL;
    public string SQL1
    {
        get { return SQL; }
        set { SQL = value; }
    }

    private int _TamanoMax;
    public int TamanoMax
    {
        get { return _TamanoMax; }
        set { _TamanoMax = value; }
    }

    private string _id;
    public string ID
    {
        get { return _id; }
        set { _id = value; }
    }

    public Capa CapaCanvas
    {
        get { return null; }
        set { }
    }

    private Colores _coloreadoBorde;
    public Colores ColoreadoBorde
    {
        get { return _coloreadoBorde; }
        set { _coloreadoBorde = value; }
    }

    private Estilo.Borde _tipoBorde;
    public Estilo.Borde TipoBorde
    {
        get { return this._tipoBorde; }
        set { this._tipoBorde = value; }
    }

    private int _alturaMax = 0;
    public int AlturaMax
    {
        get { return _alturaMax; }
        set { _alturaMax = value; }
    }

    private short _largo = 0;
    public short Largo
    {
        get { return _largo; }
        set { _largo = value; }
    }

    private float _alto = 0;
    public float Alto
    {
        get { return _alto; }
        set { _alto = value; }
    }

    private Colores _coloreado;
    public Colores Coloreado
    {
        get { return _coloreado; }
        set { _coloreado = value; }
    }

    private float _grosor;
    public float Grosor
    {
        get { return _grosor; }
        set { _grosor = value; }
    }

    private float _radio;
    public float Radio
    {
        get { return _radio; }
        set { _radio = value; }
    }

    private bool _visible;
    public bool Visible
    {
        get { return this._visible; }
        set { this._visible = value; }
    }

    private Estilo.Forma _tipoForma;
    public Estilo.Forma TipoForma
    {
        get { return this._tipoForma; }
        set { this._tipoForma = value; }
    }

    private TIPO_ENTIDAD _objEntidad;
    public TIPO_ENTIDAD TipoEntidad
    {
        get { return this._objEntidad; }
    }

    private TIPO_CAPA_SQL _TipoCapaSQL;
    public TIPO_CAPA_SQL TipoCapaSQL
    {
        get { return this._TipoCapaSQL; }
    }
    

    private Coordenada _localizacion;
    public Coordenada Localizacion
    {
        get { return _localizacion; }
        set
        {
            _localizacion = value;
        }
    }

    bool blnCompilada = false;
    /// <summary>
    /// Implementacion del metodo que es llamado por el escenario cada vez que se va a 
    /// generar un cuadro de mapa
    /// </summary>
    public unsafe void _pintar()
    {
        //Tamano de la linea y los puntos
        if (this.Visible && Escena.Localizacion.Z <= (this.AlturaMax))
        {
            if (this.Coloreado != null)
            {
                GL.Color4(this.Coloreado.Rojo, this.Coloreado.Verde, this.Coloreado.Azul, this.Coloreado.Alfa);
            }
            
            if (this.TipoCapaSQL == TIPO_CAPA_SQL.DINAMICA)
            {
                if (this.Localizacion.X != Escena.Localizacion.X || this.Localizacion.Y != Escena.Localizacion.Y ||
                this.Localizacion.Z != Escena.Localizacion.Z)
                {
                    this.Localizacion.X = Escena.Localizacion.X;
                    this.Localizacion.Y = Escena.Localizacion.Y;
                    this.Localizacion.Z = Escena.Localizacion.Z;
                    this.Construir();
                }
            }
            
        }
        if (!blnCompilada)
        {
            compilar();
        }
        GL.LineWidth(this.EntidadLargo);
        GL.CallList(_indice);
    }

    int _indice;
    /// <summary>
    /// Compila las entidades en una lista de OPENGL para no llamar cada entidad 
    /// mientras se pinta
    /// </summary>
    public unsafe void compilar()
    { 
        _indice = GL.GenLists(1);
        GL.NewList(_indice, ListMode.Compile);
        if (Coloreado!=null) {
                GL.Color4(Coloreado.Rojo, Coloreado.Verde, Coloreado.Azul, Coloreado.Alfa);
        }
        switch (this.TipoEntidad)
        {
            case TIPO_ENTIDAD.Linea:
                {
                    for (int i = 0; i <= IndiceActual; i++)
                    {
                        arrLineas[i]._pintar();
                    }
                    break;
                }
            case TIPO_ENTIDAD.Rectangulo:
                {
                    for (int i = 0; i <= IndiceActual; i++)
                    {
                        arrRectangulo[i]._pintar();
                    }
                    break;
                }
            case TIPO_ENTIDAD.Triangulo:
                {
                    for (int i = 0; i <= IndiceActual; i++)
                    {
                        arrTriangulos[i]._pintar();
                    }
                    break;
                }
        }
        GL.EndList();
        blnCompilada = true;
    }

    /// <summary>
    /// Metodo para encontrar la información de cada entidad en
    /// una coordenada dada
    /// </summary>
    /// <param name="objCoordenada"></param>
    /// <returns></returns>
    public DataTable buscarDatos(Coordenada objCoordenada)
    {
        string strConsulta="";
        DataTable objTablaRetorno=null;
        if(this.TipoEntidad!= TIPO_ENTIDAD.Linea)
        {
            strConsulta = "SELECT * FROM " + this.Tabla + " WHERE XPOS>" + (objCoordenada.X - EntidadLargo).ToString().Replace(",", ".") + "";
            strConsulta = strConsulta + " AND  XPOS<" + (objCoordenada.X + EntidadLargo).ToString().Replace(",", ".") + "";
            strConsulta = strConsulta + " AND  YPOS>" + (objCoordenada.Y - EntidadAlto).ToString().Replace(",", ".") + "";
            strConsulta = strConsulta + " AND  YPOS<" + (objCoordenada.Y + EntidadAlto).ToString().Replace(",", ".") + "";
            objTablaRetorno = Conexion.ObtenerTabla(strConsulta);
        }
        else
        {
            strConsulta = "SELECT * FROM " + this.Tabla + " WHERE XPOS1>" + (objCoordenada.X - EntidadLargo).ToString().Replace(",", ".") + "";
            strConsulta = strConsulta + " AND  XPOS1<" + (objCoordenada.X + EntidadLargo).ToString().Replace(",", ".") + "";
            strConsulta = strConsulta + " AND  YPOS1>" + (objCoordenada.Y - EntidadAlto).ToString().Replace(",", ".") + "";
            strConsulta = strConsulta + " AND  YPOS1<" + (objCoordenada.Y + EntidadAlto).ToString().Replace(",", ".") + "";
            objTablaRetorno = Conexion.ObtenerTabla(strConsulta);
        }
        return objTablaRetorno;
    }
}

